package org.batatasframework.support.charts;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ResultArrayReader {
	
	private final ChartResultParser parser;
	private final Map<String, Number[]> maps = new LinkedHashMap<>();
	
	private String[] columns;
	
	public ResultArrayReader(ChartResultParser parser){
		this.parser = parser;
	}
	public ResultArrayReader(){
		this(ChartResultParser.numberParser());
	}
	
	public String[] getColumns() {
		if(null == columns) return new String[0];
		return columns;
	}
	
	public Map<String, Number[]> getMaps() {
		return maps;
	}
	
	public void initMap(int length, String...fields){
		for(String f : fields){
			Number[] values = new Number[length];
			Arrays.fill(values, 0L);
			maps.put(f, values);
		}
	}

	private Number[] values(String name, int length){
		Number[] values = maps.get(name);
		if(null == values){
			values = new Number[length];
			Arrays.fill(values, 0L);
		}
		return values;
	}
	
	public void sumNumber(List<Object> items, ChartValuesMatcher...matchers){
		sumNumber(items, 0, matchers);
	}
	
	public void sumNumber(List<Object> items, int groudIndex, ChartValuesMatcher...matchers){
		if(null == columns){
			columns = new String[matchers.length];
			for(int i = 0; i < matchers.length; i++){
				columns[i] = matchers[i].getName();
			}
		}
		
		for(Object obj : items){
			Object[] its = (Object[])obj;
			if(null == its[groudIndex]) continue;
			
			String name = its[groudIndex].toString();
			Number[] values = values(name, matchers.length);
			for(int i = 0; i < matchers.length; i++){
				ChartValuesMatcher matcher = matchers[i];
				if(matcher.match(its)){
					values[i] = parser.add(values[i], matcher.getValue(its));
					if(!matcher.matchNext()){
						break;
					}
				}
			}
			maps.put(name, values);
		}
	}
	
	public void sumNumber(List<Object> items, ChartValueMatcher...matchColumns){
		sumNumber(items, 0, 1, 2, matchColumns);
	}
	
	public void sumNumber(List<Object> items, int nameIndex, int matchIndex, int valueIndex, ChartValueMatcher...matchColumns){
		if(null == columns){
			columns = new String[matchColumns.length];
			int i = 0;
			for(ChartValueMatcher cv : matchColumns){
				columns[i++] = cv.getName();
			}
		}
		//TODO 这里判断的时候，值与名字不一定相同的，所以不能直接使用字符串进行判断
		for(Object obj : items){
			Object[] its = (Object[])obj;

			if(null == its[nameIndex] || null == its[matchIndex]) continue;
			
			String name = its[nameIndex].toString();
			Number[] values = values(name, matchColumns.length);
			String matchValue = its[matchIndex].toString();
			Number value = (Number)its[valueIndex];
			
			for(int i = 0; i < matchColumns.length; i++){
				if(matchColumns[i].match(matchValue)){
					values[i] = parser.add(values[i], value);
					break;
				}
			}
			maps.put(name, values);
		}
	}
	
	/**
	 * <pre>
	 * 统计的属性(字段)为可选项，并且数据库存储的是可选项的下标值+1
	 * </pre>
	 */
	public void sumNumberOption(boolean multi, List<Object> items, String...options){
		sumNumberOption(multi, items, 0, 1, 2, options);
	}
	
	/**
	 * <pre>
	 * 统计的属性(字段)为可选项，并且数据库存储的是可选项的下标值
	 * </pre>
	 */
	public void sumNumberOption2(boolean multi, List<Object> items, String...options){
		sumNumberOption2(multi, items, 0, 1, 2, options);
	}
	
	
	public void sumNumberOption(boolean multi, List<Object> items, int nameIndex, int optionIndex, int valueIndex, String...options){
		if(null == columns){
			columns = options;
		}
		for(Object obj : items){
			Object[] its = (Object[])obj;

			if(null == its[nameIndex] || null == its[optionIndex]) continue;
			
			String name = its[nameIndex].toString();
			Number[] values = values(name, options.length);
			
			int oi = ((Number)its[optionIndex]).intValue();
			Number lval = ((Number)its[valueIndex]);
			if(multi){
				for(int i = 0; i < options.length; i++){
					if((oi & (1 << i)) > 0){
						values[i] = parser.add(values[i], lval);
					}
				}
			}else{
				oi -= 1;
				if(0 <= oi && oi < options.length){
					values[oi] = parser.add(values[oi], lval);
				}
			}
			maps.put(name, values);
		}
	}
	public void sumNumberOption2(boolean multi, List<Object> items, int nameIndex, int optionIndex, int valueIndex, String...options){
		if(null == columns){
			columns = options;
		}
		for(Object obj : items){
			Object[] its = (Object[])obj;

			if(null == its[nameIndex] || null == its[optionIndex]) continue;
			
			String name = its[nameIndex].toString();
			Number[] values = values(name, options.length);
			
			int oi = ((Number)its[optionIndex]).intValue();
			Number lval = ((Number)its[valueIndex]);
			if(multi){
				for(int i = 0; i < options.length; i++){
					if((oi & (1 << i)) > 0){
						values[i] = parser.add(values[i], lval);
					}
				}
			}else{
				if(0 <= oi && oi < options.length){
					values[oi] = parser.add(values[oi], lval);
				}
			}
			maps.put(name, values);
		}
	}
	public void sumFields(List<Object> items, String...fields){
		sumFields(items, 0, 1, fields);
	}
	
	public void sumFields(List<Object> items, int nameIndex, int offset, String...fields){
		if(null == columns){
			columns = fields;
		}
		for(Object obj : items){
			Object[] its = (Object[])obj;
			if(null == its[nameIndex]) continue;

			String name = its[nameIndex].toString();
			Number[] values = values(name, fields.length);
			
			for(int i = 0; i < fields.length; i++){
				values[i] = parser.add(values[i], its, i + offset);
			}
			maps.put(name, values);
		}

	}
}
